#ifndef xpack_lang_wxx
#define xpack_lang_wxx
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_wxx::inc
#include"define/base_type.hpp"
#include"macro/xstruct.hpp"
#include"macro/xexport.hpp"
#include"meta/unsigned_type.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_wxx{
    template<class type_t>
    xstruct(
        xtmpl(wxx, type_t),
        xprof(m_value, type_t)
    )

    public:
        xprops()
            xpubgetx(is_alpha, bool){
                xr{
                    // 0x41 0100 0001
                    // 0x61 0110 0001
                    auto mask = xthe.m_value | 0x20;
                    return 'a' <= mask && mask <= 'z';
                }
            };

            xpubgetx(is_ascii, bool){
                xr{ return inc::unsigned_type<type_t>(xthe.m_value) < 128; }
            };

            xpubgetx(is_control, bool){
                xr{ return xthe.m_value <= 0x1f or (0x7f <= xthe.m_value and xthe.m_value <= 0x9f); }
            };

            xpubgetx(is_digital, bool){
                xr{ return '0' <= xthe.m_value and xthe.m_value <= '9'; }
            };

            xpubgetx(is_hex, bool){
                xr{ 
                    auto mask = xthe.m_value | 0x20;
                    return ('0' <= xthe.m_value and xthe.m_value <= '9') or ('a' <= mask and mask <= 'f');
                }
            };

            xpubgetx(is_lower_hex, bool){
                xr{ return ('0' <= xthe.m_value and xthe.m_value <= '9' ) or ('a' <= xthe.m_value and xthe.m_value <= 'f'); }
            };

            xpubgetx(is_lower, bool){
                xr{ return ('a' <= xthe.m_value and xthe.m_value <= 'z'); }
            };

            xpubgetx(is_primary_char, bool){
                xr{
                    if constexpr (sizeof(xthe.m_value) == sizeof(char)){
                        return (u08(xthe.m_value) & 0x80) != 0;
                    }
                    return true;
                }
            };

            xpubgetx(is_punctuation, bool){
                xr{ return xthe.is_punctuation(); }
            };

            xpubgetx(is_upper_hex, bool){
                xr{ return ('0' <= xthe.m_value and xthe.m_value <= '9' ) or ('A' <= xthe.m_value and xthe.m_value <= 'F'); }
            };

            xpubgetx(is_upper, bool){
                xr{ return ('A' <= xthe.m_value and xthe.m_value <= 'Z'); }
            };

            xpubgetx(is_whitespace, bool){
                xr{
                    return
                        xthe.m_value == 0x09 or
                        xthe.m_value == 0x0a or
                        xthe.m_value == 0x0b or
                        xthe.m_value == 0x0c or
                        xthe.m_value == 0x0d or
                        xthe.m_value == 0x20 or
                        xthe.m_value == 0x85 or
                        xthe.m_value == 0xa0;
                }
            };

            xpubgetx(length_if_as_utf8, uxx){
                xr{ return xthe.length_if_as_utf8(); }
            };
        $

        xprops_operator()

    public:
        constexpr wxx() : m_value('\0'){};
        constexpr wxx(wxx const &) = default;
        constexpr wxx(type_t value) : m_value(value){}

        operator type_t & (){
            return m_value;
        }
    
    public:
        uxx parse_hex() const;
        the_t to_lower() const;
        the_t to_upper() const;
    private:
        bool is_punctuation() const;
        uxx length_if_as_utf8() const;
    $
}

namespace mixc::lang_wxx::origin{
    using ::mixc::lang_wxx::wxx;

    using w08 = wxx<char>;
    using w16 = wxx<char16_t>;
}

#endif

xexport_space(mixc::lang_wxx::origin)
